/*
 * -------------------------------------- 
 * FileName: mono_list.c 
 * Content:
 *      mono-way linked list.
 * 
 * Auther:  杨则瑞 
 * Encode:  utf-8 | CRLF                  
 * -------------------------------------- 
 */



#include<mono_list.h>
#include<debuging.h>





#define ns(title) monoList_##title



static int ns(insert_by_ptr) (ns(t) *, ns(node_t) *, const void *);
static int ns(erasenext_by_ptr) (ns(t) *, ns(node_t) *);




int ns(init) (ns(t) * self, size_t elem_size)
{
    int status = 0;

    *self = (ns(t)) {
        ._header = NULL, 
        ._elem_size = elem_size
    };

    self->_header = 
        (ns(node_t) *)malloc(sizeof(ns(node_t)));

    if(self->_header == NULL)
    {
        _debug("Allocation Fault","WARN");
        status = 1;
    }
    else
    {
        *self->_header = (ns(node_t)) {
            .next = NULL,
        };
    }
    return status;
}

int ns(uninit) (ns(t) * self)
{
    self->_elem_size = 0;
    ns(node_t) * p = self->_header;
    while (p->next != NULL)
    {
        ns(node_t) *tbd = p->next;
        p->next = tbd->next;
        free(tbd);
    }
    free(self->_header);
    self->_header = NULL;
    return 0;
}

int ns(clear) (ns(t) * self)
{
    ns(node_t) * p = self->_header;
    while (p->next != NULL)
    {
        ns(node_t) *tbd = p->next;
        p->next = tbd->next;
        free(tbd);
    }
    return 0;
}

int ns(insert) (ns(t) * self, size_t pos,
                const void * element)
{
    int status = 0;
    ns(node_t) * p_pre = self->_header;

    for(int i = 0; i < pos; ++ i){
        if(p_pre == NULL)
        {
            status = -1;
            _debug("Index Out Of Range[0,len].\nOperation Aborted","WARN");
            return status;
        }
        p_pre = p_pre->next;
    }
    
    status = ns(insert_by_ptr)(self,p_pre,element);
    return status;
}


int ns(erase) (ns(t) * self, size_t pos)
{
    int status = 0;
    ns(node_t) * p_pre = self->_header;

    if(self->_header->next == NULL) {
        status = -1;
        _debug("Error: Delete from empty list.\nOperation Aborted","WARN");    
        return status;
    }

    for(int i = 0; i < pos; ++ i){
        if(p_pre->next == NULL)
        {
            status = -1;
            _debug("Index Out Of Range[0,len-1].\nOperation Aborted","WARN");
            return status;
        }
        p_pre = p_pre->next;
    }

    status = ns(erasenext_by_ptr)(self,p_pre);

    return status;
}



int ns(is_empty) (const ns(t) * self)
{
    return self->_header->next == NULL;
}

size_t ns(length) (const ns(t) * self)
{
    ns(node_t) * p = self->_header->next;
    size_t cnt = 0;
    while (p != NULL)
    {
        ++ cnt;
        p = p->next;
    }
    return cnt;
}

int ns(get) (const ns(t) * self, size_t pos, void * val_dest)
{
    ns(node_t) * p_pre = self->_header->next;

    if(self->_header->next == NULL) {
        _debug("Error: get from empty list.\nOperation Aborted","WARN");    
        return -1;
    }

    for(int i = 0; i < pos; ++ i){
        if(p_pre == NULL)
        {
            _debug("Index Out Of Range[0,len-1].\nOperation Aborted","WARN");
            return -1;
        }
        p_pre = p_pre->next;
    }

    memcpy(val_dest,p_pre->data,self->_elem_size);
    return 0;
}





static int ns(insert_by_ptr) (ns(t) * self, ns(node_t) *pre_node,
                const void * element)
{
    int status = 0;
    ns(node_t) * p_newElem =
        (ns(node_t) *)malloc(self->_elem_size+sizeof(ns(node_t)));
    
    if(p_newElem == NULL)
    {
        _debug("Allocation Fault","WARN");
        status = 1;
    }
    else
    {
        p_newElem->next = pre_node->next;
        memcpy(p_newElem->data,element,self->_elem_size);
        pre_node->next = p_newElem;
    }

    return status;
}


static int ns(erasenext_by_ptr) (ns(t) * self, ns(node_t) *pre_node)
{
    if(pre_node == NULL || pre_node->next == NULL) {
        return -2;
    }
    ns(node_t) *tbd = pre_node->next;
    pre_node->next = tbd->next;
    free(tbd);
}



#undef ns 

